﻿namespace mgen_commonDlg
{
    using System;
    using System.Collections.Generic;
    using System.Windows;
    using System.Windows.Controls;
    using System.Windows.Controls.Primitives;
    using System.Windows.Input;

    public abstract class CommonDialogControl : Control
    {
        #region Fields

        public static readonly DependencyProperty ButtonStyleProperty = 
            DependencyProperty.Register("ButtonStyle", typeof(Style), typeof(CommonDialogControl),
                new FrameworkPropertyMetadata((Style)null));
        public static readonly DependencyProperty CommandProperty = 
            DependencyProperty.Register("Command", typeof(ICommand), typeof(CommonDialogControl),
                new FrameworkPropertyMetadata((ICommand)null,
                    new PropertyChangedCallback(OnCommandChanged)));
        public static readonly DependencyProperty CommandTextProperty = 
            DependencyProperty.Register("CommandText", typeof(string), typeof(CommonDialogControl),
                new PropertyMetadata((string)null));
        public static readonly DependencyProperty FilterProperty = 
            DependencyProperty.Register("Filter", typeof(string), typeof(CommonDialogControl),
                new FrameworkPropertyMetadata((string)null));
        public static readonly RoutedEvent OpenedEvent = EventManager.RegisterRoutedEvent("Opened",
            RoutingStrategy.Bubble, typeof(RoutedEventHandler), typeof(CommonDialogControl));
        public static readonly DependencyProperty PathProperty = 
            DependencyProperty.Register("Path", typeof(string), typeof(CommonDialogControl),
                new FrameworkPropertyMetadata((string)null, FrameworkPropertyMetadataOptions.BindsTwoWayByDefault,
                    new PropertyChangedCallback(OnPathChanged)));
        public static readonly RoutedEvent ShownEvent = EventManager.RegisterRoutedEvent("Shown",
            RoutingStrategy.Bubble, typeof(EventHandler<CommonDialogShownEventArgs>), typeof(CommonDialogControl));
        public static readonly DependencyProperty TextBoxStyleProperty = 
            DependencyProperty.Register("TextBoxStyle", typeof(Style), typeof(CommonDialogControl),
                new FrameworkPropertyMetadata((Style)null));

        protected const string PART_Button = "PART_ButtonBase";

        ButtonBase buttonBase;

        #endregion Fields

        #region Constructors

        public CommonDialogControl()
        {
            AllowDrop = true;
            DragEnter += OpenFileControl_DragEnter;
            Drop += OpenFileControl_Drop;
        }

        #endregion Constructors

        #region Events

        public event RoutedEventHandler Opened
        {
            add { AddHandler(OpenedEvent, value); }
            remove { RemoveHandler(OpenedEvent, value); }
        }

        public event EventHandler<CommonDialogShownEventArgs> Shown
        {
            add { AddHandler(ShownEvent, value); }
            remove { RemoveHandler(ShownEvent, value); }
        }

        #endregion Events

        #region Properties

        public Style ButtonStyle
        {
            get { return (Style)GetValue(ButtonStyleProperty); }
            set { SetValue(ButtonStyleProperty, value); }
        }

        public ICommand Command
        {
            get { return (ICommand)GetValue(CommandProperty); }
            set { SetValue(CommandProperty, value); }
        }

        public string CommandText
        {
            get { return (string)GetValue(CommandTextProperty); }
            set { SetValue(CommandTextProperty, value); }
        }

        public string Filter
        {
            get { return (string)GetValue(FilterProperty); }
            set { SetValue(FilterProperty, value); }
        }

        public string Path
        {
            get { return (string)GetValue(PathProperty); }
            set { SetValue(PathProperty, value); }
        }

        public Style TextBoxStyle
        {
            get { return (Style)GetValue(TextBoxStyleProperty); }
            set { SetValue(TextBoxStyleProperty, value); }
        }

        #endregion Properties

        #region Methods

        public abstract void Browse();

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            buttonBase = Template.FindName(PART_Button, this) as ButtonBase;
            if (buttonBase != null)
            {
                buttonBase.Click += (ss, ee) => Browse();
                if (Command != null)
                {
                    var window = Window.GetWindow(this);
                    if (window != null)
                    {
                        var cmdBinding = new CommandBinding(Command, (ss, ee) => Browse());
                        window.CommandBindings.Add(cmdBinding);
                    }
                }
            }
        }

        protected virtual void OnCommandChanged(ICommand oldCommand, ICommand newCommand)
        {
        }

        protected virtual void OnOpened()
        {
            var e = new RoutedEventArgs(OpenedEvent);
            e.Source = this;
            RaiseEvent(e);
        }

        protected virtual void OnPathChanged(string oldPath, string newPath)
        {
        }

        protected virtual void OnShown(bool? res)
        {
            var e = new CommonDialogShownEventArgs(ShownEvent, res);
            e.Source = this;
            RaiseEvent(e);
        }

        private static void OnCommandChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CommonDialogControl target = (CommonDialogControl)d;
            ICommand oldCommand = (ICommand)e.OldValue;
            ICommand newCommand = target.Command;
            target.OnCommandChanged(oldCommand, newCommand);
        }

        private static void OnPathChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            CommonDialogControl target = (CommonDialogControl)d;
            string oldPath = (string)e.OldValue;
            string newPath = target.Path;
            target.OnPathChanged(oldPath, newPath);
        }

        void OpenFileControl_DragEnter(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
                e.Effects = DragDropEffects.Copy;
            else
                e.Effects = DragDropEffects.None;

            e.Handled = true;
        }

        void OpenFileControl_Drop(object sender, DragEventArgs e)
        {
            if (e.Data.GetDataPresent(DataFormats.FileDrop))
            {
                var files = e.Data.GetData(DataFormats.FileDrop) as string[];
                if (files != null && files.Length > 0)
                    Path = files[0];
            }
        }

        #endregion Methods
    }

    public class CommonDialogShownEventArgs : RoutedEventArgs
    {
        #region Constructors

        public CommonDialogShownEventArgs(RoutedEvent re, bool? res)
            : base(re)
        {
            Result = res;
        }

        #endregion Constructors

        #region Properties

        public bool? Result
        {
            get; private set;
        }

        #endregion Properties
    }
}